﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using SLNGP.Core.GeneticPrograms;
using SLNGP.Core.Individuals;
using SLNGP.Core.Run;

namespace SLNGP.Core.Genes
{
    public interface IGene
    {
        /// <summary>
        /// Executes the current Gene and activates it's phenotype.
        /// </summary>
        /// <param name="data">The context in which the gene is activated.</param>
        /// <returns>Null if procedure. Evaluated value of the function / constant / variable if not.</returns>
        object Execute(IGeneticProgrammingRun data);
        
        /// <summary>
        /// Gets the display used to debug this gene. 
        /// </summary>
        /// <returns></returns>
        string GetStringDisplay();

        /// <summary>
        /// The list of children nested under this Gene.
        /// </summary>
        ObservableCollection<IGene> Children { get; }

        /// <summary>
        /// Gets a value indicating whether the Gene is valid.
        /// </summary>
        bool IsValid { get; }

        /// <summary>
        /// The Gene Return Type.
        /// Returns null if the gene is a procedure.
        /// </summary>
        Type GeneReturnType { get; }

        /// <summary>
        /// If the current gene does not have a valid genotype, initiates a self fix. 
        /// </summary>
        void Fix();

        /// <summary>
        /// Replaces an old gene with a replacement gene.
        /// </summary>
        /// <param name="newGene">The replacement gene.</param>
        void ReplaceWith(IGene newGene);

        /// <summary>
        /// Clones a gene for child clone. 
        /// </summary>
        /// <param name="parentGene">The parent gene.</param>
        /// <param name="parentChromosome">the parent chromosome (with ParentGeneticProgram and ParentIndividual).</param>
        /// <returns>Clone of Gene.</returns>
        IGene ChildClone(IGene parentGene, IChromosome parentChromosome);

        /// <summary>
        /// Gets or sets the GeneDefinition used to generate this Gene.
        /// </summary>
        IGeneDefinition GeneDefinition { get; set; }

        IGeneticProgram ParentGeneticProgram { get; }
        IIndividual ParentIndividual { get;  }
        IChromosome ParentChromosome { get; set; }
        IGene ParentGene { get; set; }
    }
}